﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using WcfContrib.Helpers;
using System.ServiceModel.Configuration;
using System.Configuration;

namespace WcfContrib.Extensions.Context
{
    /// <summary>
    /// Represents a service behavior responsible for extending the service activation
    /// </summary>
    public class ActivationContextInitializerBehavior : IServiceBehavior
    {
        internal const bool DefaultCreateMessageBuffer = false;
        internal const bool DefaultCreateBufferForErrors = false;

        ActivationContextInspector inspector;

        private bool createMessageBuffer = DefaultCreateMessageBuffer;
        /// <summary>
        /// Gets or sets a value indicating whether to create a message buffer.
        /// </summary>
        /// <value><c>true</c> if to create a message buffer; otherwise, <c>false</c>.</value>
        public bool CreateMessageBuffer
        {
            get { return createMessageBuffer; }
            set
            {
                createMessageBuffer = value;

                if (inspector != null)
                {
                    inspector.CreateMessageBuffer = value;
                }
            }
        }

        private bool createBufferForErrors = DefaultCreateBufferForErrors;
        internal bool CreateBufferForErrors
        {
            get { return createBufferForErrors; }
            set
            {
                createBufferForErrors = value;

                if (inspector != null)
                {
                    inspector.CreateBufferForErrors = value;
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActivationContextInitializerBehavior"/> class.
        /// </summary>
        public ActivationContextInitializerBehavior()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActivationContextInitializerBehavior"/> class.
        /// </summary>
        /// <param name="createMessageBuffer">if set to <c>true</c>, A message buffer is created.</param>
        public ActivationContextInitializerBehavior(bool createMessageBuffer)
        {
            CreateMessageBuffer = createMessageBuffer;
        }

        #region IServiceBehavior Members

        void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            serviceDescription.Behaviors.AddSafely(() => new SessionContextExtensionBehavior());

            inspector = new ActivationContextInspector(CreateMessageBuffer);
            inspector.CreateBufferForErrors = CreateBufferForErrors;
            inspector.ServiceType = serviceDescription.ServiceType;
            inspector.ServiceName = serviceDescription.Name;
            inspector.ServiceNamespace = serviceDescription.Namespace;

            foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
            {
                foreach (var ep in chanDisp.Endpoints)
                {
                    ep.DispatchRuntime.MessageInspectors.Add(inspector);

                    foreach (var op in ep.DispatchRuntime.Operations)
                    {
                        op.ParameterInspectors.Add(inspector);
                    }
                }
            }
        }

        void IServiceBehavior.Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }

        #endregion
    }

    /// <summary>
    /// Represents a service behavior attribute responsible for extending the service activation
    /// </summary>
    public class ActivationContextInitializerAttribute : Attribute, IServiceBehavior
    {
        ActivationContextInitializerBehavior behavior;

        /// <summary>
        /// Gets or sets a value indicating whether to create a message buffer.
        /// </summary>
        /// <value><c>true</c> if to create a message buffer; otherwise, <c>false</c>.</value>
        public bool CreateMessageBuffer
        {
            get { return behavior.CreateMessageBuffer; }
            set { behavior.CreateMessageBuffer = value; }
        }

        internal bool CreateBufferForErrors
        {
            get { return behavior.CreateBufferForErrors; }
            set { behavior.CreateBufferForErrors = value; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActivationContextInitializerBehavior"/> class.
        /// </summary>
        public ActivationContextInitializerAttribute()
        {
            behavior = new ActivationContextInitializerBehavior();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActivationContextInitializerBehavior"/> class.
        /// </summary>
        /// <param name="createMessageBuffer">if set to <c>true</c>, A message buffer is created.</param>
        public ActivationContextInitializerAttribute(bool createMessageBuffer)
            : this()
        {
            CreateMessageBuffer = createMessageBuffer;
        }

        #region IServiceBehavior Members

        void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            serviceDescription.Behaviors.AddSafely(() => behavior);
        }

        void IServiceBehavior.Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }

        #endregion
    }

    /// <summary>
    /// Represents an activation context extension behavior element
    /// </summary>
    public class ActivationContextExtensionBehaviorElement : BehaviorExtensionElement
    {
        /// <summary>
        /// Gets or sets a value indicating whether to create a message buffer.
        /// </summary>
        /// <value><c>true</c> if to create a message buffer; otherwise, <c>false</c>.</value>
        [ConfigurationProperty("createMessageBuffer", DefaultValue = ActivationContextInitializerBehavior.DefaultCreateMessageBuffer)]
        public bool CreateMessageBuffer
        {
            get
            {
                return (bool)base["createMessageBuffer"];
            }
            set
            {
                base["createMessageBuffer"] = value;
            }
        }

        private ConfigurationPropertyCollection properties = null;
        /// <summary>
        /// Gets the collection of properties.
        /// </summary>
        protected override System.Configuration.ConfigurationPropertyCollection Properties
        {
            get
            {
                if (properties == null)
                {
                    properties = new ConfigurationPropertyCollection();

                    properties.Add(new ConfigurationProperty("createMessageBuffer",
                        typeof(bool), ActivationContextInitializerBehavior.DefaultCreateMessageBuffer));
                }

                return properties;
            }
        }

        /// <summary>
        /// Gets the type of behavior.
        /// </summary>
        public override Type BehaviorType
        {
            get { return typeof(ActivationContextInitializerBehavior); }
        }

        /// <summary>
        /// Creates a behavior extension based on the current configuration settings.
        /// </summary>
        /// <returns></returns>
        protected override object CreateBehavior()
        {
            return new ActivationContextInitializerBehavior(CreateMessageBuffer);
        }
    }
}
